// TreeModel.cpp
#include "TreeModel.h"
#include <QFile>
#include <QTextStream>
#include <QVariant>
#include <QMap>

TreeItem::TreeItem(const QVariant &data, TreeItem *parent)
    : itemData(data), parentItem(parent) {}

TreeItem::~TreeItem() {
    qDeleteAll(childItems);
}

TreeItem *TreeItem::child(int number) {
    return childItems.value(number);
}

int TreeItem::childCount() const {
    return childItems.count();
}

int TreeItem::columnCount() const {
    return itemData.toList().count();
}

QVariant TreeItem::data(int column) const {
    return itemData.toList().value(column);
}

bool TreeItem::insertChildren(int position, int count, int columns) {
    if (position < 0 || position > childItems.count()) {
        return false;
    }

    for (int row = 0; row < count; ++row) {
        QMap<int, QVariant> map;
        map.insert(columns, QVariant());
        TreeItem *item = new TreeItem(QVariant::fromValue(map), this);
        childItems.insert(position, item);
    }

    return true;
}

bool TreeItem::insertColumns(int position, int count) {
    if (position < 0 || position > itemData.toList().count()) {
        return false;
    }

    for (int column = 0; column < count; ++column) {
        itemData.toList().insert(position, QVariant());
    }

    for (TreeItem *child : std::as_const(childItems)) {
        child->insertColumns(position, count);
    }

    return true;
}

TreeItem *TreeItem::parent() {
    return parentItem;
}

bool TreeItem::removeChildren(int position, int count) {
    if (position < 0 || position + count > childItems.count()) {
        return false;
    }

    for (int row = 0; row < count; ++row) {
        delete childItems.takeAt(position);
    }

    return true;
}

bool TreeItem::removeColumns(int position, int count) {
    if (position < 0 || position + count > itemData.toList().count()) {
        return false;
    }

    for (int column = 0; column < count; ++column) {
        itemData.toList().removeAt(position);
    }

    for (TreeItem *child : std::as_const(childItems)) {
        child->removeColumns(position, count);
    }

    return true;
}

int TreeItem::row() const {
    if (parentItem) {
        return parentItem->childItems.indexOf(const_cast<TreeItem *>(this));
    }

    return 0;
}

bool TreeItem::setData(int column, const QVariant &value) {
    if (column < 0 || column >= itemData.toList().count()) {
        return false;
    }

    itemData.toList().replace(column, value);
    return true;
}

TreeModel::TreeModel(const QStringList &headers, QObject *parent)
    : QAbstractItemModel(parent) {
    rootItem = new TreeItem(headers);
}

TreeModel::~TreeModel() {
    delete rootItem;
}

QVariant TreeModel::data(const QModelIndex &index, int role) const {
    if (!index.isValid() || role != Qt::DisplayRole) {
        return QVariant();
    }

    TreeItem *item = static_cast<TreeItem *>(index.internalPointer());
    return item->data(index.column());
}

Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const {
    if (!index.isValid()) {
        return Qt::NoItemFlags;
    }

    return QAbstractItemModel::flags(index);
}

QVariant TreeModel::headerData(int section, Qt::Orientation orientation, int role) const {
    if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
        return rootItem->data(section);
    }

    return QVariant();
}

QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const {
    if (!hasIndex(row, column, parent)) {
        return QModelIndex();
    }

    TreeItem *parentItem = nullptr;

    if (!parent.isValid()) {
        parentItem = rootItem;
    } else {
        parentItem = static_cast<TreeItem *>(parent.internalPointer());
    }

    TreeItem *childItem = parentItem->child(row);
    if (childItem) {
        return createIndex(row, column, childItem);
    }

    return QModelIndex();
}

QModelIndex TreeModel::parent(const QModelIndex &index) const {
    if (!index.isValid()) {
        return QModelIndex();
    }

    TreeItem *childItem = static_cast<TreeItem *>(index.internalPointer());
    TreeItem *parentItem = childItem->parent();

    if (parentItem == rootItem) {
        return QModelIndex();
    }

    return createIndex(parentItem->row(), 0, parentItem);
}

int TreeModel::rowCount(const QModelIndex &parent) const {
    TreeItem *parentItem = nullptr;

    if (parent.column() > 0) {
        return 0;
    }

    if (!parent.isValid()) {
        parentItem = rootItem;
    } else {
        parentItem = static_cast<TreeItem *>(parent.internalPointer());
    }

    return parentItem->childCount();
}

int TreeModel::columnCount(const QModelIndex &parent) const {
    if (parent.isValid()) {
        return static_cast<TreeItem *>(parent.internalPointer())->columnCount();
    } else {
        return rootItem->columnCount();
    }
}

bool TreeModel::insertColumns(int position, int columns, const QModelIndex &parent) {
    beginInsertColumns(parent, position, position + columns - 1);

    bool success = rootItem->insertColumns(position, columns);

    endInsertColumns();

    return success;
}

bool TreeModel::insertRows(int position, int rows, const QModelIndex &parent) {
    TreeItem *parentItem = nullptr;

    if (parent.isValid()) {
        parentItem = static_cast<TreeItem *>(parent.internalPointer());
    } else {
        parentItem = rootItem;
    }

    beginInsertRows(parent, position, position + rows - 1);

    bool success = parentItem->insertChildren(position, rows, rootItem->columnCount());

    endInsertRows();

    return success;
}

bool TreeModel::removeColumns(int position, int columns, const QModelIndex &parent) {
    beginRemoveColumns(parent, position, position + columns - 1);

    bool success = rootItem->removeColumns(position, columns);

    endRemoveColumns();

    return success;
}

bool TreeModel::removeRows(int position, int rows, const QModelIndex &parent) {
    TreeItem *parentItem = nullptr;

    if (parent.isValid()) {
        parentItem = static_cast<TreeItem *>(parent.internalPointer());
    } else {
        parentItem = rootItem;
    }

    beginRemoveRows(parent, position, position + rows - 1);

    bool success = parentItem->removeChildren(position, rows);

    endRemoveRows();

    return success;
}

void TreeModel::setupModelData(const QStringList &lines, TreeItem *parent) {
    TreeItem *parentItem = parent;
    TreeItem *grandparentItem = parent->parent();
    int indentLevel = 0;

    for (const QString &line : lines) {
        int spaceCount = 0;
        int i = 0;

        while (i < line.length() && line.at(i) == ' ') {
            ++spaceCount;
            ++i;
        }

        QString data = line.mid(i).trimmed();

        if (!data.isEmpty()) {
            int column = 0;

            if (spaceCount > indentLevel) {
                if (parentItem->childCount() > 0) {
                    parentItem = parentItem->child(parentItem->childCount() - 1);
                }
                indentLevel = spaceCount;
            } else {
                while (spaceCount < indentLevel && parentItem != nullptr) {
                    parentItem = parentItem->parent();
                    --indentLevel;
                }
            }

            parentItem->insertChildren(parentItem->childCount(), 1, 1);
            parentItem->child(parentItem->childCount() - 1)->setData(0, data);
        }
    }
}
